package edu.ccut.saturn.osgi;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.felix.framework.Felix;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.main.AutoActivator;
import org.apache.felix.main.Main;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleException;

import edu.ccut.saturn.component.SaturnComponentException;
import edu.ccut.saturn.component.utils.PropertyUtils;
import edu.ccut.saturn.core.impl.HostActivator;

/**
 * 本类可以启动,关闭OSGI容器.
 * <p>
 * 通过配置文件config.properties对OSGI容器进行配置; 加载指定路径下的所有Osgi bundles;
 * <p>
 * 
 * @author LeslieGu,TonyYan
 */
public class OSGiBundleLoader {

	private static final String AUTO_START_PROP = "felix.auto.start";

	private Felix felix = null;

	private String configFileLocation;

	private String bundlesHomeLocation;

	private Map<String, String> configMap;

	public OSGiBundleLoader(String configFileLocation,
			String bundlesHomeLocation) {

		this.configFileLocation = configFileLocation;
		this.bundlesHomeLocation = bundlesHomeLocation;
		initConfigMap();
		clearCache();

	}

	/**
	 * 启动osgi容器
	 */
	public void startup() throws Exception {

		List<BundleActivator> list = new ArrayList<BundleActivator>();
		list.add(new AutoActivator(configMap));
		list.add(HostActivator.getInstance());
		felix = new Felix(configMap, list);
		felix.start();
	}

	/**
	 * 停止osgi容器
	 */
	public void shutdown() {

		// 利用独立的线程确保OSGI容器关闭
		Thread close = new Thread() {
			public void run() {
				try {
					felix.stop();
				} catch (BundleException e) {
					e.printStackTrace();
				}
			}
		};
		close.start();
	}

	/**
	 * 初始化configMap
	 */
	private void initConfigMap() {

		configMap = new HashMap<String, String>();
		initalConfigMapFromProperties();
		initalAutoStartBundles();
	}

	/**
	 * 添加需要加载的bundle到configMap
	 */
	private void initalAutoStartBundles() {

		int frameworkStartLevel = 1;

		try {
			frameworkStartLevel = Integer.parseInt(configMap
					.get(FelixConstants.FRAMEWORK_STARTLEVEL_PROP));
		} catch (NumberFormatException e) {
			e.printStackTrace(); // To change body of catch statement use
			// File | Settings | File Templates.
		}

		int i = 1;
		StringBuffer allBundlesFileNames = new StringBuffer();
		for (; i < frameworkStartLevel; ++i) {
			initBundleInDirectory(allBundlesFileNames, i + "", i);
		}
		// 加载plugins文件夹下的Bundles
		initBundleInDirectory(allBundlesFileNames, "plugins", i);

		List<String> filtedBundleFileList = new ArrayList<String>();
		try {
			filtedBundleFileList = OSGIBundleLoaderUtil.queryBundleUnused();
		} catch (SaturnComponentException e) {
			e.printStackTrace();
		}
		/**
		 * 删除数据库中冗余bundle信息
		 */
		if (filtedBundleFileList.size() > 0) {
			for (String bundleFile : filtedBundleFileList) {
				if (allBundlesFileNames.indexOf(bundleFile) == -1) {
					try {
						OSGIBundleLoaderUtil.deleteBundlefromDB(bundleFile);

					} catch (SaturnComponentException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * 初始化将完成<br>
	 * 1、将bundle目录下的bundle名拼接后推入configMap<br>
	 * 2、将bundle目录下的bundle名拼接后追加到allBundlesFileNames
	 * 
	 * @param allBundlesFileNames
	 * @param directory
	 * @param level
	 */
	private void initBundleInDirectory(StringBuffer allBundlesFileNames,
			String directory, int level) {
		String allBundlesFileNamesFromDirectory = getAllBundlesFileNamesFromDirectory(bundlesHomeLocation
				+ System.getProperty("file.separator") + directory);

		String bundlesFileNames = getBundlesFilteredFileNames(allBundlesFileNamesFromDirectory);

		if (bundlesFileNames != null) {
			configMap.put(AUTO_START_PROP + "." + level, bundlesFileNames);
		}

		if (allBundlesFileNamesFromDirectory != null) {
			allBundlesFileNames.append(allBundlesFileNamesFromDirectory);
		}
	}

	/**
	 * 将制定路径下的bundle名称拼接返回
	 * 
	 * @param directory
	 * @return file:aBundle.jar file:bBundle.jar
	 */
	private String getAllBundlesFileNamesFromDirectory(String directory) {
		File firstDir = new File(directory);
		if (firstDir.exists()) {
			File[] bundlesNames = firstDir.listFiles(new FileFilter() {
				public boolean accept(File pathname) {
					return pathname.getName().endsWith(".jar");
				}
			});
			if (bundlesNames != null) {
				StringBuffer bundlesNamesBuffer = new StringBuffer();
				for (File bundlesName : bundlesNames) {
					bundlesNamesBuffer.append("file:" + bundlesName.getPath()
							+ " ");

				}
				return bundlesNamesBuffer.toString();
			}
		}

		return null;
	}

	/**
	 * 从bundle名拼接字符串中过滤不可用的bundle
	 * 
	 * @param fullBundlesFileName
	 * @return
	 */
	private String getBundlesFilteredFileNames(String fullBundlesFileName) {
		if (fullBundlesFileName == null || "".equals(fullBundlesFileName)) {
			return null;
		}

		StringBuffer filterFileName = new StringBuffer(fullBundlesFileName);

		// 查看bundlesinfo表是否包含status为disable的bundle，如果有从bundlesNames中去掉
		List<String> bundleFileList = null;
		try {
			bundleFileList = OSGIBundleLoaderUtil.queryBundleUnused();
		} catch (SaturnComponentException e) {
			e.printStackTrace();
			return fullBundlesFileName.toString();
		}

		if (bundleFileList != null) {
			for (String bundleFile : bundleFileList) {
				if (filterFileName.indexOf(bundleFile) != -1) {
					int start = filterFileName.indexOf(bundleFile);
					int end = start + bundleFile.length();
					filterFileName.delete(start, end);
				}
			}
		}
		return filterFileName.toString();
	}

	/**
	 * 加载OSGI配置文件
	 */
	@SuppressWarnings("unchecked")
	private void initalConfigMapFromProperties() {

		Properties configProperties = PropertyUtils
				.loadProperties(configFileLocation);

		Enumeration enumeration = configProperties.propertyNames();
		while (enumeration.hasMoreElements()) {
			String key = (String) enumeration.nextElement();
			configMap.put(key, Main.substVars(
					configProperties.getProperty(key), key, null,
					configProperties));

		}
		// TODO 服务名截取方法不健壮

		String[] bundlesHomeLocationsplit = bundlesHomeLocation.split(System
				.getProperty("file.separator")
				+ System.getProperty("file.separator"));
		
		if("\\".equals(File.separator)){//window
			bundlesHomeLocationsplit = bundlesHomeLocation.split("\\\\");
		} else {
			bundlesHomeLocationsplit = bundlesHomeLocation.split(System.getProperty("file.separator"));
		}
		
		String serverName = bundlesHomeLocationsplit[bundlesHomeLocationsplit.length - 3];
		configMap.put("felix.cache.dir", serverName + "_cache");
	}

	/**
	 * 清除缓存信息
	 */
	private void clearCache() {
		String profileDirName = configMap.get("felix.cache.profile");
		String cacheDirName = configMap.get("felix.cache.dir");

		File profileDir = new File(cacheDirName
				+ System.getProperty("file.separator") + profileDirName);

		if (profileDir.isDirectory()) {
			deleteDirectory(profileDir);
		} else {
			profileDir.delete();
		}

		profileDir.mkdir();
		// profileDir.deleteOnExit();
	}

	private static void deleteDirectory(File dir) {
		File[] files = dir.listFiles();
		for (int i = 0; i < files.length; i++) {
			if (files[i].isDirectory()) {
				deleteDirectory(files[i]);
			} else {
				files[i].delete();
			}
		}
		dir.delete();
	}
}
